<template>
  <ElForm
    ref="form"
    :key="data.id"
    :model="data"
    :rules="rules"
    size="mini"
    class="fa-widget-setting fa-contract-scope"
    @click.stop.native
    @submit.native.prevent
  >
    <slot name="start" v-bind="{ data }" />

    <fieldset class="form-fieldset">
      <ElFormItem v-if="visible.widgetName" prop="name" label="控件名称">
        <ElInput
          class="el-input__limit-clearable"
          v-model="data.name"
          :disabled="disabled"
          :maxlength="50"
          placeholder="请输入控件名称"
          clearable
          show-word-limit
          @blur="data.name = data.name.trim()"
        />
      </ElFormItem>

      <ElFormItem v-if="visible.widgetActor" prop="actor.id" label="参与方设置">
        <template #label>
          参与方设置
          <ElTooltip effect="dark" content="未设置参与方的填写控件，使用时将由“发起方”填写" placement="top">
            <i class="fa-widget-setting__label-tips fa-icon-info"></i>
          </ElTooltip>
        </template>

        <ElSelect
          v-model="actorId"
          popper-class="fa-contract-scope"
          :disabled="disabled"
          placeholder="请选择参与方"
          :clearable="!data.actorRequired"
        >
          <ElOption
            v-if="!data.actorRequired"
            value=""
            label="未设置"
            class="fa-widget-setting__actor-option actor-color00"
          ></ElOption>

          <ElOption
            v-for="item in actorList"
            :key="item.id"
            :value="item.id"
            :label="item.name"
            :class="`fa-widget-setting__actor-option actor-${getActorColor(item.index)}`"
            :disabled="actorDisable(item)"
          />
        </ElSelect>
      </ElFormItem>

      <Components :is="data.option.settingComponent" :viewer="viewer" :data="data" :disabled="disabled" />

      <ElFormItem v-if="data.isFill && !data.option.settingCustomFillRequirements" prop="required" label="填写要求">
        <ElCheckbox v-model="data.required" :disabled="disabled">必填</ElCheckbox>
      </ElFormItem>

      <ElFormItem v-if="visible.widgetCode" prop="extra.code" label="控件编码" :disabled="disabled">
        <ElInput
          class="el-input__limit-clearable"
          v-model="data.extra.code"
          :maxlength="widgetCodeMaxLength"
          :disabled="disabled"
          placeholder="请输入控件编码"
          show-word-limit
          clearable
          @blur="fixWidgetCode"
        />
      </ElFormItem>

      <slot v-bind="{ data }" />
    </fieldset>
  </ElForm>
</template>

<script lang="ts">
import { computed, defineComponent, nextTick, PropType, reactive, ref, toRef, watch } from 'vue'
import { Widget } from '@/models'
import { Viewer, WidgetType, ActorData } from '@/types'
import { ElForm } from '@/types/thirdParty'

export default defineComponent({
  name: 'FaWidgetSetting',

  props: {
    /** 控件数据 */
    data: {
      type: Widget,
      required: true
    },

    /**
     * 文档查看组件
     * @description 有些控件的设置项依赖文档查看组件的配置，因此请尽可能提供
     */
    viewer: Object as PropType<Viewer>,

    /** 是否显示控件名称字段 */
    widgetName: {
      type: [Boolean, Function] as PropType<boolean | ((widget: Widget) => boolean)>,
      default: true
    },

    /** 是否显示参与方设置字段 */
    widgetActor: {
      type: [Boolean, Function] as PropType<boolean | ((widget: Widget) => boolean)>,
      default: true
    },

    /** 参与方列表 */
    actors: {
      type: Array as PropType<ActorData[]>,
      required: true
    },

    /** 参与方是否禁用 */
    actorDisable: {
      type: Function as PropType<(item: ActorData) => boolean>,
      default: () => false
    },

    /** 是否展示控件编码字段 */
    widgetCode: {
      type: [Boolean, Function] as PropType<boolean | ((widget: Widget) => boolean)>,
      default: false
    },

    /** 控件编码长度 */
    widgetCodeMaxLength: {
      type: Number,
      default: 32
    },

    /** 控件编码是否必填 */
    widgetCodeRequired: {
      type: Boolean,
      default: true
    }
  },

  setup(props, { emit }) {
    /** 表单控件 */
    const form = ref(null as null | ElForm)

    /** 控件数据 */
    const data = toRef(props, 'data')

    /** 可见 */
    const visible = reactive({
      /** 是否显示控件名称字段 */
      widgetName: computed(() => getBooleanProp(props.widgetName)),

      /** 是否显示参与方设置字段 */
      widgetActor: computed(() => getBooleanProp(props.widgetActor)),

      /** 是否展示控件编码字段 */
      widgetCode: computed(() => getBooleanProp(props.widgetCode))
    })

    /** 获取布尔值参数 */
    function getBooleanProp(prop: boolean | ((widget: Widget) => boolean), propDefault?: boolean) {
      if (typeof prop == 'boolean') return prop

      if (typeof prop == 'function') return prop(props.data)

      return propDefault ?? true
    }

    /** 可见参与方列表 */
    const actorList = computed(() => {
      const widget = data.value
      const { actors } = props

      // 填写方
      if (widget.isFill) {
        return actors.filter(actor => !!actor.fill)
      } else {
        // 签署方
        let list = actors.filter(actor => !!actor.sign)

        // 印章控件屏蔽个人参与方
        if (widget.type === WidgetType.SEAL) {
          list = list.filter(actor => !actor.isPerson)
        }

        // 骑缝控件屏蔽当前文档已有骑缝控件参与方
        if (widget.isRiding) {
          const { viewer } = props

          if (!viewer) return list

          // 当前页骑缝控件（排除当前控件）已绑定的参与方
          const ridingActors = viewer.docRidings
            .filter(item => item.id !== widget.id && item.actor.id)
            .map(item => item.actor.id)

          list = list.filter(actor => !ridingActors.includes(actor.id))
        }

        return list
      }
    })

    /** 清除校验 */
    function clearValidate() {
      form.value?.clearValidate()
      emit('clear-validate')
    }

    watch(data, async () => {
      await nextTick()
      clearValidate()
    })

    return {
      /** 表单控件 */
      form,

      /** 可见 */
      visible,

      /** 获取参与方颜色 */
      getActorColor: Widget.getActorColor,

      /** 可见参与方列表 */
      actorList,

      /** 参与方选择 */
      actorId: computed({
        set(val) {
          data.value.actor = props.actors.find(item => item.id === val) || {
            id: '',
            name: '',
            index: -1
          }
        },

        get: () => data.value.actor.id
      }),

      /** 控件是否只读 */
      disabled: computed(() => data.value.isView || data.value.isDone),

      /** 表单校验 */
      rules: computed(() => {
        const { nameRequired, actorRequired } = props.data
        return {
          name: nameRequired ? [{ required: true, message: '请输入控件名称', trigger: 'blur' }] : [],

          'actor.id': actorRequired ? [{ required: true, message: '请选择参与方', trigger: 'change' }] : [],

          'extra.code': props.widgetCodeRequired ? [{ required: true, message: '请输入控件编码', trigger: 'blur' }] : []
        }
      }),

      /** 触发校验 */
      validate() {
        emit('trigger-validate')
        return form.value?.validate()
      },

      /** 清除校验 */
      clearValidate,

      /** 修正控件编码 */
      fixWidgetCode() {
        const { extra } = props.data
        extra.code = ((extra.code as string) || '').replace(/\s+/g, '')
      }
    }
  }
})
</script>

<style lang="scss">
/** 左右间距 */
$space: 16px;

.fa-widget-setting {
  .form-fieldset {
    margin: 0;
    padding: 8px $space $space;
    border: none;
    border-bottom: $border-solid;

    &:last-child {
      border-bottom: none;
    }
  }

  .el-form-item {
    &.el-form-item--mini {
      margin-bottom: 8px;
    }

    &__label {
      padding: 0;
    }

    &__content {
      font-size: 12px;
      line-height: 2;
    }
  }

  .form-fieldset > .el-form-item:last-child {
    margin-bottom: 0;
  }

  &__label-tips {
    margin-top: 2px;
    margin-left: 6px;
    color: $color-info-light;
    font-size: 14px;
  }

  /** 选项列表 */
  &__option-list {
    margin: 0 #{-$space};
    padding: 0 #{$space};
    overflow: auto;
  }

  &__actor-option {
    position: relative;

    &::before {
      position: absolute;
      top: 50%;
      left: 10px;
      width: 2px;
      height: 1em;
      margin-top: -0.5em;
      vertical-align: middle;
      content: '';
    }

    &.is-disabled {
      color: $color-text-disabled !important;

      &::before {
        opacity: 0.5;
      }
    }

    @each $c, $color in $actor-colors {
      &.actor-#{$c}::before {
        background-color: $color;
      }
    }
  }
}
</style>
